﻿using System.Collections.Generic;
using Quartz;
using Quartz.Impl;
using System.Reflection;
using Quartz.Spi;
using QW.Found.AutoTasks;
using QW.Core.AutoTasks;

namespace QW.Found.TasksTasks.Quartz
{
    /// <summary>
    /// Quartz任务中心
    /// </summary>
    public class QuartzTaskCenter : BaseTaskCenter<JobKey>
    {
        //调度器
        protected readonly IScheduler scheduler;
        /// <summary>
        /// .ctor
        /// </summary>
        /// <param name="scheduler"></param>
        public QuartzTaskCenter(IScheduler scheduler)
        {
            this.scheduler = scheduler;
        }
        /// <summary>
        /// .ctor
        /// </summary>
        /// <param name="factory">调度器工厂</param>
        /// <param name="jobFactory"></param>
        public QuartzTaskCenter(ISchedulerFactory factory, IJobFactory jobFactory)
        {
            this.scheduler = factory.GetScheduler().GetAwaiter().GetResult();
            this.scheduler.JobFactory = jobFactory;
        }
        /// <summary>
        /// 构建任务
        /// </summary>
        /// <param name="detail"></param>
        /// <returns></returns>
        private IJobDetail BuilderJob(TaskDescriptor<JobKey> detail)
        {
            var job = JobBuilder.Create<TaskJob>()
                .WithIdentity(detail.Name, detail.Group)
                .SetJobData(new JobDataMap {
                    { "TaskDescriptor", detail }
                }).Build();
            detail.Key = job.Key;
            return job;
        }

        /// <summary>
        /// 构建触发器
        /// </summary>
        /// <param name="detail"></param>
        /// <returns></returns>
        private ITrigger BuilderTrigger(TaskDescriptor<JobKey> detail)
        {
            var interval = detail.Interval;
            var builder = TriggerBuilder.Create()
                .WithIdentity(detail.Name + "Trigger", detail.Group);

            if (interval.Type == TaskIntervalType.Seconds)
            {
                builder.WithSimpleSchedule(x => x
                    .WithIntervalInSeconds(interval.SecondsValue)
                    .RepeatForever());
            }
            else if (interval.Type == TaskIntervalType.Daily)
            {
                builder.WithDailyTimeIntervalSchedule(x =>
                x.StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(interval.DailyValue.Hours, interval.DailyValue.Minutes))
                .EndingDailyAfterCount(1)
                .WithIntervalInHours(1));
            }
            else if (interval.Type == TaskIntervalType.Cron)
            {
                builder.WithCronSchedule(interval.CronExpression);
            }
            return builder.Build();
        }

        /// <summary>
        /// 订阅
        /// </summary>
        /// <param name="descriptor"></param>
        protected override void Subscribe(TaskDescriptor<JobKey> descriptor)
        {
            var job = BuilderJob(descriptor);
            var trigger = BuilderTrigger(descriptor);
            scheduler.ScheduleJob(job, trigger);
        }
        /// <summary>
        /// 改变触发条件
        /// </summary>
        /// <param name="descriptor"></param>
        /// <param name="interval"></param>
        protected override void ChangeTrigger(TaskDescriptor<JobKey> descriptor, TaskInterval interval)
        {
            descriptor.Interval = interval;
            scheduler.ResumeJob(descriptor.Key);
            Subscribe(descriptor);
        }

        /// <summary>
        /// 启动
        /// </summary>
        public async override void Start()
        {
            await scheduler.Start();
        }
        /// <summary>
        /// 停止
        /// </summary>
        public async override void Stop()
        {
            await scheduler?.Shutdown(true);
        }
        /// <summary>
        /// 析构
        /// </summary>
        public override void Dispose()
        {
            Stop();
            base.Dispose();
        }
    }
}
